package com.ljb.readaloud.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.Log;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码生成和解析的工具类
 * Created by lijianbin on 2017/1/7.
 */
public class BitMatrixTool {

    private static final String TAG = BitMatrixTool.class.getSimpleName();
    private static BitMatrixTool tool;

    private void BitMatrix() {
    }

    public static BitMatrixTool init() {
        if (tool == null)
            tool = new BitMatrixTool();
        return tool;
    }

    /**
     * 由字符串生成一个Bitmap对象
     *
     * @param contents 字符串内容
     * @param width    目标宽
     * @param height   目标高
     * @return Bitmap对象
     */
    public Bitmap createQRCodeBitmap(String contents, int width, int height) {
        return bitMatrixToBitmap(encode(contents, width, height));
    }

    /**
     * 将Bitmap对象解析成字符串
     *
     * @param bitmap 二维码对象
     * @return 字符串
     */
    public String decodeQRCode(Bitmap bitmap) {
        return decode(bitmap);
    }

    /**
     * 将Bitmap对象保存到指定路径
     *
     * @param path   保存路径
     * @param bitmap 图片对象
     * @return 是否保存成功
     */
    public boolean saveQRCodeBitmap(String path, Bitmap bitmap) {
        return saveQRCodeBitmap(path, bitmap, 100);
    }


    /**
     * 获取带有logo的二维码的bitmap对象
     *
     * @param contents 二维码内容
     * @param width    二维码宽
     * @param height   二维码高
     * @param logo     logo的bitmap对象
     * @return
     */
    public Bitmap createLogoQRCodeBitmap(String contents, int width, int height, Bitmap logo) {
        return addLogo(createQRCodeBitmap(contents, width, height), logo);
    }

    /*************************************分割线***********************************************/

    private boolean saveQRCodeBitmap(String path, Bitmap bitmap, int quality) {
        File file = new File(path);
        if (file.exists()) {
            file.delete();
        }
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, quality, fos);
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.i(TAG, "二维码图片保存失败!");
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            Log.i(TAG, "二维码图片保存失败!");
            return false;
        } finally {
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Log.i(TAG, "二维码图片保存成功!");
        return true;
    }

    private BitMatrix encode(String contents, int width, int height) {
        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            return new QRCodeWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
            return null;
        }
    }

    private Bitmap bitMatrixToBitmap(BitMatrix bitMatrix) {
        if (bitMatrix == null)
            return null;
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        int[] pixels = new int[width * height];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                pixels[y * width + x] = bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF;
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

    private String decode(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        RGBLuminanceSource luminanceSource = new RGBLuminanceSource(width, height, pixels);
        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));
        try {
            Map<DecodeHintType, Object> hints = new HashMap<>();
            hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
            hints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);
            hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
            Result result = new QRCodeReader().decode(binaryBitmap, hints);
            return result.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 添加logo
     *
     * @param src
     * @param logo
     * @return
     */
    private Bitmap addLogo(Bitmap src, Bitmap logo) {
        if (src == null)
            return null;
        if (logo == null)
            return src;
        //获取图片的宽高
        int srcWidth = src.getWidth();
        int srcHeight = src.getHeight();
        int logoWidth = logo.getWidth();
        int logoHeight = logo.getHeight();

        if (srcWidth == 0 || srcHeight == 0)
            return null;
        if (logoWidth == 0 || logoHeight == 0)
            return src;
        //logo大小为二维码整体大小的1/5
        float scaleWidth = srcWidth * 1.0f / 5 / logoWidth;
        float scaleHeight = srcHeight * 1.0f / 5 / logoHeight;
        Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
        try {
            Canvas canvas = new Canvas(bitmap);
            canvas.drawBitmap(src, 0, 0, null);
            canvas.scale(scaleWidth, scaleHeight, srcWidth / 2, srcHeight / 2);
            canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);
            canvas.save(Canvas.ALL_SAVE_FLAG);
            canvas.restore();
            return bitmap;
        } catch (Exception e) {
            e.getStackTrace();
        }
        return null;
    }
}
